﻿using System;
using System.Collections.Generic;
using Microsoft.Practices.Unity;
using JTLeigh.Commerce.Spencer.Core.Common;
using JTLeigh.Commerce.Spencer.Core.Service.Contracts;
using JTLeigh.Commerce.Spencer.Features.ProductFeedback.Business;
using JTLeigh.Commerce.Spencer.Features.ProductFeedback.Business.Services;

// aliases for entities
using ProductFeedbackE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductFeedback;

// aliases for contracts
using GetProductFeedbackSummariesRequestC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedbackSummaries.GetProductFeedbackSummariesRequest;
using GetProductFeedbackSummariesResponseC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedbackSummaries.GetProductFeedbackSummariesResponse;
using ProductFeedbackSummaryC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedbackSummaries.ProductFeedbackSummary;

namespace JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Commands.Runtime
{

	/// <summary>
	/// Command for getting summaries of the feedback for multiple products, including total and 
	/// average ratings, total and positive recommendations, and total reviews.
	/// </summary>
	public class GetProductFeedbackSummariesCommand
	{

		#region Properties

		/// <summary>
		/// Gets or sets the product feedback metadata service to use to get product feedback 
		/// metadata.
		/// </summary>
		/// <value>An <see cref="IProductFeedbackMetadataService"/> implementation.</value>
		[Dependency]
		public IProductFeedbackMetadataService ProductFeedbackMetadataService { get; set; }

		/// <summary>
		/// Gets or sets the product feedback service to use to get product feedback.
		/// </summary>
		/// <value>An <see cref="IProductFeedbackRuntimeService"/> implementation.</value>
		[Dependency]
		public IProductFeedbackRuntimeService ProductFeedbackRuntimeService { get; set; }

		#endregion // Properties

		#region Methods

		/// <summary>
		/// Gets summaries of the feedback for multiple products, including total and average
		/// ratings, total and positive recommendations, and total reviews.
		/// </summary>
		/// <param name="request">The <see cref="GetProductFeedbackSummariesRequestC"/> request
		/// object.</param>
		/// <returns>The <see cref="GetProductFeedbackSummariesResponseC"/> response object.</returns>
		public GetProductFeedbackSummariesResponseC GetProductFeedbackSummaries(GetProductFeedbackSummariesRequestC request)
		{
			GetProductFeedbackSummariesResponseC response;
			IList<ProductFeedbackE> feedback;
			BreakdownAveragingCounter ratingCounter;
			BooleanCounter recommendationCounter;
			int totalReviews;
			ProductFeedbackSummaryC summary;

			Safety.AssertArgumentNotNull("request", request);

			response = new GetProductFeedbackSummariesResponseC
			{
				Summaries = new Dictionary<FullyQualifiedProductId, ProductFeedbackSummaryC>(),
			};

			ratingCounter = new BreakdownAveragingCounter();
			recommendationCounter = new BooleanCounter();

			foreach (FullyQualifiedProductId productId in request.ProductIds)
			{

				feedback = ProductFeedbackRuntimeService.GetProductFeedback(request.TenantId, productId.CatalogId, productId.ProductId, request.SelectionBehaviorName);

				ratingCounter.Reset();
				recommendationCounter.Reset();
				totalReviews = 0;

				foreach (ProductFeedbackE feedbackE in feedback)
				{
					if (feedbackE.Rating != null)
					{
						ratingCounter.AddValue(feedbackE.Rating.Value);
					}
					if (feedbackE.Recommendation != null)
					{
						recommendationCounter.AddValue(feedbackE.Recommendation.Value);
					}
					if (feedbackE.Review != null)
					{
						totalReviews++;
					}
				}

				summary = new ProductFeedbackSummaryC
				{
					TotalRatings = ratingCounter.Count,
					AverageRatingValue = ratingCounter.Average,
					TotalRecommendations = recommendationCounter.Count,
					PositiveRecommendations = recommendationCounter.PositiveCount,
					TotalReviews = totalReviews,
				};
				response.Summaries.Add(productId, summary);

			}

			return response;
		}

		#endregion // Methods

	}

}
